﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace Faust.Andrew.MTG.Player
{
	/// <summary>
	/// Interaction logic for PlaySurface.xaml
	/// </summary>
    partial class PlaySurface : UserControl, ITableView
	{
        static PlaySurface()
        {
            PresenterProperty = DependencyProperty.Register("Presenter", typeof(GamePresenter), typeof(PlaySurface));
        }

        private Dictionary<int, PlayerSurface> _playerSurface;

        public PlaySurface()
        {
            this.InitializeComponent();            
        }
        #region ITableView
        static DependencyProperty PresenterProperty;
        public GamePresenter Presenter
        {
            get
            {
                return (GamePresenter)base.GetValue(PresenterProperty);
            }
            set
            {
                base.SetValue(PresenterProperty, value);
            }
        }

        public System.Windows.Point MeasurePlayArea(int playerID)
        {
            Point point = new Point();
            point.X = _playerSurface[playerID].ActualWidth;
            point.Y = _playerSurface[playerID].ActualHeight;
            return point;
        }

        public System.Windows.Point MeasureCard(int cardID)
        {
            foreach (PlayerSurface surface in _playerSurface.Values)
            {
                if (surface.ContainsCard(cardID))
                {
                    return surface.MeasureCard(cardID);
                }
            }

            return new Point(226, 311);
        }

        public double GetRotation(FrameworkElement element)
        {
            foreach (PlayerSurface surface in _playerSurface.Values)
            {
                if (surface.IsAncestorOf(element))
                {
                    if (surface.RenderTransform != null && surface.RenderTransform is RotateTransform)
                    {
                        return (surface.RenderTransform as RotateTransform).Angle;
                    }
                    else
                    {
                        return 0;
                    }
                }
            }

            return 0;
        }

        public void RefreshPlayers()
        {
            SetPlayers();
        }
        #endregion

        private void SetPlayers()
        {
            ClearPlayers();

            _playerSurface = new Dictionary<int, PlayerSurface>();
            PlayerSurface tempPlayerArea = new PlayerSurface();

            TableMetrics metrics = CalculateCircle(new Point() { X = tempPlayerArea.Width, Y = tempPlayerArea.Height }, Presenter.Model.Players.Count);
            Width = metrics.TableSize.X;
            Height = metrics.TableSize.Y;

            Ellipse ellipse = new Ellipse();
            ellipse.Fill = new SolidColorBrush(Colors.DarkOliveGreen);
            ellipse.Width = Width;
            ellipse.Height = Height;
            Canvas.SetZIndex(ellipse, 0);
            canvasTable.Children.Add(ellipse);

            int order = Presenter.Model.CurrentPlayer.Order;

            for (int i = 0; i < Presenter.Model.Players.Count; i++)
            {
                PlayerState tempPlayerState = Presenter.Model.Players[i];

                tempPlayerArea = new PlayerSurface(Presenter, tempPlayerState, this);
                tempPlayerArea.IsHitTestVisible = true;
                canvasTable.Children.Add(tempPlayerArea);
                Canvas.SetZIndex(tempPlayerArea, 10);
                if (Presenter.Model.IsCurrentPlayer(tempPlayerState.PlayerID))
                {
                    Canvas.SetZIndex(tempPlayerArea, 20);
                }
                
                Canvas.SetLeft(tempPlayerArea, metrics.PlayAreaStartingLocation.X);
                Canvas.SetTop(tempPlayerArea, metrics.PlayAreaStartingLocation.Y);                               

                RotateTransform rotation = new RotateTransform();
                Point rotationOrigin = new Point();

                rotationOrigin.X = metrics.PlayAreaRotationPoint.X;
                rotationOrigin.Y = metrics.PlayAreaRotationPoint.Y;

                //Uncomment for render transform
                tempPlayerArea.SetValue(RenderTransformOriginProperty, rotationOrigin);                

                rotation.Angle = metrics.RotationAngle * ((double)tempPlayerState.Order - order);
                tempPlayerArea.RenderTransform = rotation;
                _playerSurface.Add(tempPlayerState.PlayerID, tempPlayerArea);
            }
        }    
        
        private void ClearPlayers()
        {
            canvasTable.Children.Clear();
        }

        #region Math
        
        private TableMetrics CalculateCircle(Point playAreaSize, int numberOfPlayers)
        {
            /*
             * Calculate the size of the table and the angle of the rotation needed to space
             * the players equadistantly around a cirlcular table.
             * 
             * Step 1: Find Degree of the Arc for each player's space (360 / #Players)
             * Step 2: Calculate Radius of circle the top bound of the play areas are attached to.
             * Step 2a: Sin(Arc/2) = (Width / 2)/Radius -> (sin(>) = O/H)
             * Step 3: Calculate Length from center of circle to the top edge of the player area
             * Step 3a: Cos(Arc/2) = A/Radius -> Cos(>) = A/H
             * Step 4: Calculate the size of the table. It will be the diameter of the circle
             *         which is bounded by the bottom of the play area.
             * Step 4a: Use pythagorean's theorem a^2 + b^2 = c^2
             * Step 4b: a = (Width/2), b = distanceToTop + height
             * Step 5: Set TableSize = Outer Circle's Diameter
             */
            TableMetrics metrics = new TableMetrics();

            double oppositeLength = playAreaSize.X / 2.0;
            double rotationAngle = 360.0 / ((double)numberOfPlayers);
            double angle = rotationAngle / 2.0;
            double sinAngle = Math.Sin(Helper.Utility.DegreesToRadians(angle));
            double cosAngle = Math.Cos(Helper.Utility.DegreesToRadians(angle));

            double radius = oppositeLength / sinAngle;
            double distanceToPlayArea = radius * cosAngle;

            double outerCircleRadius = Helper.Utility.CalculatePythagorean(distanceToPlayArea + playAreaSize.Y, oppositeLength);

            metrics.TableSize.X = outerCircleRadius * 2.0;
            metrics.TableSize.Y = outerCircleRadius * 2.0;

            //The top of the play area needs to be just high enough off the bottom of the table so that the circle formed by the
            //table just touches the bottom corners. 
            metrics.PlayAreaStartingLocation.Y = metrics.TableSize.Y - playAreaSize.Y - (outerCircleRadius - (distanceToPlayArea + playAreaSize.Y));
            metrics.PlayAreaStartingLocation.X = (metrics.TableSize.X - playAreaSize.X) / 2.0;

            metrics.CircleCenter.X = metrics.TableSize.X / 2.0;
            metrics.CircleCenter.Y = metrics.TableSize.Y / 2.0;

            metrics.RotationAngle = rotationAngle;

            metrics.PlayAreaRotationPoint.X = 0.5;
            metrics.PlayAreaRotationPoint.Y = -(distanceToPlayArea / playAreaSize.Y);

            return metrics;
        }

        
        #endregion

    }
}